package io.hepu.robotize.util;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class JDate {

    private static final String DEFAULT_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    private static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";

    private static final String DEFAULT_TIME_PATTERN = "HH:mm:ss";

    private JDate() {
        // not supported instance
    }

    private static final List<String> patterns = new ArrayList<String>() {{
        add("yyyy-MM-dd HH:mm:ss");
        add("yyyy-MM-dd HH:mm");
        add("yyyy-MM-dd HH");
        add("yyyy-MM-dd");
    }};

    /***
     * 转换字符串为日期date
     *
     * 自动匹配转化，支持patterns中的几种格式
     * @param ds string of date
     * @param pi index of patterns
     * @return
     */
    public static Date parse(String ds, int... pi) {
        int index = 0;
        if (pi != null && pi.length > 0) {
            index = pi[0];
        }
        if (index > patterns.size() - 1) {
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat(patterns.get(index));
        try {
            return format.parse(ds);
        } catch (ParseException e1) {
            return parse(ds, ++index);
        }
    }

    /**
     * Get date part string from given date
     *
     * @param date given date
     */
    public static String date(Date date) {
        return format(date, DEFAULT_DATE_PATTERN);
    }

    /**
     * Get time part string from given date
     *
     * @param date given date
     */
    public static String time(Date date) {
        return format(date, DEFAULT_TIME_PATTERN);
    }

    /**
     * Format the date in the default format
     *
     * @param date given date
     */
    public static String format(Date date) {
        return format(date, DEFAULT_DATETIME_PATTERN);
    }

    /**
     * Format the date in the specific format
     *
     * @param date    given date
     * @param pattern format pattern
     */
    public static String format(Date date, String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * Format current time in the specific format
     * @param pattern format pattern
     */
    public static String format(String pattern) {
        return new SimpleDateFormat(pattern).format(now());
    }

    /**
     * Parse the given string to date in the default format
     *
     * @param ds string of date
     */
    public static Date parse(String ds) {
        return parse(ds, DEFAULT_DATETIME_PATTERN);
    }

    /**
     * Parse the given string to date in the specific format
     *
     * @param ds      string of date
     * @param pattern format pattern
     */
    public static Date parse(String ds, String pattern) {
        if (pattern == null) {
            throw new NullPointerException("Given arguments must not be null");
        }
        try {
            return new SimpleDateFormat(pattern).parse(ds);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Get timestamp from given date
     *
     * @param date given date
     */
    public static Timestamp timestamp(Date date) {
        return new Timestamp(date.getTime());
    }

    /**
     * Get date from given milliseconds
     *
     * @param mills given milliseconds
     */
    public static Date parse(long mills) {
        return new Date(mills);
    }

    /**
     * Get now date
     */
    public static Date now() {
        return parse(System.currentTimeMillis());
    }

    /**
     * Get tomorrow date
     *
     * @TODO LocalDate.now().plusDays(1);
     */
    public static Date tomorrow() {
        // get a calendar instance, which defaults to "now"
        Calendar calendar = Calendar.getInstance();
        // add one day to the date/calendar
        calendar.add(Calendar.DAY_OF_YEAR, 1);
        return calendar.getTime();
    }

    /**
     * Get zero date
     */
    public static Date zero() {
        return parse(100000000000L);
    }

    /**
     * Check given local datetime is between intervals
     *
     * @param start   the time start
     * @param endline the time end
     * @return true if the time is between given intervals
     */
    public static boolean isBetween(LocalDateTime start, LocalDateTime endline) {
        LocalDateTime now = LocalDateTime.now();
        return now.isAfter(start) && now.isBefore(endline);
    }

    /**
     * Check given date is between intervals
     *
     * @param start   the time start
     * @param endline the time end
     * @return true if the time is between given intervals
     */
    public static boolean isBetween(Date start, Date endline) {
        Date now = now();
        return now.after(start) && now.before(endline);
    }

    public static Date plusDays(int interval) {
        LocalDate localDate = LocalDate.now().plusDays(interval);
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

}
